package com.zys.el.time.service.impl;

import cn.hutool.core.lang.Snowflake;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zys.el.time.common.exception.sql.SqlException;
import com.zys.el.time.constants.MQConstants;
import com.zys.el.time.constants.RedisConstants;
import com.zys.el.time.dto.CommentDTO;
import com.zys.el.time.dto.ScrollPage;
import com.zys.el.time.entity.Comment;
import com.zys.el.time.mapper.CommentMapper;
import com.zys.el.time.mq.constants.ModeType;
import com.zys.el.time.mq.dto.MqDTO;
import com.zys.el.time.service.CommentService;
import com.zys.el.time.service.redis.CacheClient;
import com.zys.el.time.vojo.CommentVo;
import com.zys.el.time.vojo.RepliedVo;
import com.zys.el.time.vojo.UserVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment>
        implements CommentService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private UserService userService;
    @Resource
    private RabbitTemplate rabbitTemplate;
    @Resource
    private CacheClient cacheClient;


    @Override
    public Boolean addComment(CommentDTO commentDTO) {
        Comment comment = new Comment();
        BeanUtils.copyProperties(commentDTO, comment);

        // 生成雪花id
        Snowflake snowflake = new Snowflake();
        long commentId = snowflake.nextId();
        comment.setCommentId(commentId);
        comment.setStatus(2); // 设置审核中的状态
        comment.setCreateTime(LocalDateTime.now());
        String commentJsonStr = JSON.toJSONString(comment);
        // 存入redis
        String key = RedisConstants.COMMENT_KEY + commentId;
        stringRedisTemplate.opsForValue().set(key, commentJsonStr);
        // 存入消息队列
        MqDTO mqDTO = new MqDTO(commentJsonStr, ModeType.SAVE);
        log.debug(String.valueOf(mqDTO));
        rabbitTemplate.convertAndSend(MQConstants.COMMENT_KEY, mqDTO);

        // 返回添加成功
        return true;
    }

    @Override
    public void removeByIdWithReplied(String commentId, String rid) {
        Comment comment = this.getById(commentId);
        boolean b;
        if (comment.getRootCommentId() == null) { // 一级评论
            QueryWrapper<Comment> qw = new QueryWrapper<>();
            qw.lambda().eq(Comment::getCommentId, commentId)
                    .or()
                    .eq(Comment::getRootCommentId, commentId);
            b = this.remove(qw);
            String key = RedisConstants.PAGE_COMMENT_KEY + rid;
            stringRedisTemplate.opsForZSet().remove(key, commentId);
        } else {
            b = this.removeById(commentId);
            String key = RedisConstants.PAGE_REPLIED_KEY + rid;
            stringRedisTemplate.opsForZSet().remove(key, commentId);
        }

        if (!b) {
            throw new SqlException("删除评论异常");
        }
    }


    private List<Comment> queryCommentPage(Map<String, Object> map){
        Long id = (Long) map.get("id");
        Long startIdx = (Long) map.get("startIdx");
        int size = (int) map.get("size");
        return this.baseMapper.getRootCommentPageByThinkingId(id, startIdx, size);
    }


    @Override
    public ScrollPage<CommentVo> getRootCommentPage(Long thinkingId, Long max, int offset, int size) {
        String commentPageKey = RedisConstants.PAGE_COMMENT_KEY + thinkingId;

        HashMap<String, Object> map = new HashMap<>();
        map.put("id", thinkingId);
        return cacheClient.queryScrollPage(commentPageKey, map, max, offset, size,
                this::getCommentVoById, this::queryCommentPage, RedisConstants.COMMON_TTL, TimeUnit.MINUTES);

    }


    private List<Comment> queryRepliedPage(Map<String, Object> map){
        Long id = (Long) map.get("id");
        Long startIdx = (Long) map.get("startIdx");
        int size = (int) map.get("size");
        return this.baseMapper.getRepliedCommentPageByThinkingId(id, startIdx, size);
    }

    @Override
    public ScrollPage<RepliedVo> getRepliedPage(Long rootCommentId, Long max, int offset, int size) {
        String repliedPageKey = RedisConstants.PAGE_REPLIED_KEY + rootCommentId;

        HashMap<String, Object> map = new HashMap<>();
        map.put("id", rootCommentId);
        return cacheClient.queryScrollPage(repliedPageKey, map, max, offset, size,
                this::getRepliedVoById, this::queryRepliedPage);
    }

    @Override
    public RepliedVo getRepliedVoById(Long commentId) {
        String rootCommentKey = RedisConstants.COMMENT_KEY + commentId;

        Comment comment = cacheClient.queryWithoutLock(rootCommentKey, commentId, Comment.class, this::getById,
                RedisConstants.COMMENT_TTL, RedisConstants.NULL_TTL, TimeUnit.MINUTES);

        // 用户信息
        UserVo owner = userService.queryUser(comment.getUserId());
        UserVo repliee = userService.queryUser(comment.getReplieeId());

        // todo 点赞数

        RepliedVo repliedVo = new RepliedVo();
        BeanUtils.copyProperties(comment, repliedVo);
        repliedVo.setOwner(owner);
        repliedVo.setRepliee(repliee);
        return repliedVo;
    }


    @Override
    public CommentVo getCommentVoById(Long commentId) {
        String rootCommentKey = RedisConstants.COMMENT_KEY + commentId;

        Comment comment = cacheClient.queryWithoutLock(rootCommentKey, commentId, Comment.class, this::getById,
                RedisConstants.COMMENT_TTL, RedisConstants.NULL_TTL, TimeUnit.MINUTES);

        UserVo userVo = userService.queryUser(comment.getUserId());
        // todo 获取点赞数

        return this.getCommentVo(comment, userVo);
    }


    private CommentVo getCommentVo(Comment comment, UserVo userVo) {
        CommentVo commentVo = new CommentVo();
        BeanUtils.copyProperties(comment, commentVo);
        commentVo.setOwner(userVo);
        return commentVo;
    }


}




